package com.spzx.product.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.bean.BeanUtils;
import com.spzx.product.api.domain.vo.*;
import com.spzx.product.api.domain.vo.Product;
import com.spzx.product.domain.SkuStock;
import com.spzx.product.mapper.*;
import com.spzx.product.service.IProductService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class IProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
    @Resource
    ProductMapper productMapper;

    @Resource
    ProductSkuMapper productSkuMapper;
    @Resource
    ProductDetailsMapper productDetailsMapper;
    @Resource
    SkuStockMapper skuStockMapper;
    @Resource
    RedissonClient redissonClient;
    @Resource
    RedisTemplate redisTemplate;



    @Override
    public List<Product> selectProductList(Product product) {

        return baseMapper.selectProdutList(product);
    }

    @Override
    public int insertProduct(Product product) {
        //插入product表
        baseMapper.insert(product);
        //返回product主键
        Long productId = product.getId();
        //插入sku表
        List<ProductSku> productSkuList = product.getProductSkuList();
        int i = 0;
        for (ProductSku productSku : productSkuList
        ) {
            productSku.setProductId(productId);
            String skuName = product.getName() + " " + productSku.getSkuSpec();
            productSku.setSkuName(skuName);
            String skuCode = productId + "_" + i;
            productSku.setSkuCode(skuCode);
            productSkuMapper.insert(productSku);
            Long skuId = productSku.getId();


            //插入stock表
            SkuStock skuStock = new SkuStock();
            skuStock.setSkuId(skuId);
            skuStock.setAvailableNum(productSku.getStockNum());
            skuStock.setTotalNum(productSku.getStockNum());
            skuStock.setLockNum(0);
            skuStock.setSaleNum(0);
            skuStockMapper.insert(skuStock);
            i++;
        }

        //插入海报
        List<String> detailsImageUrlList = product.getDetailsImageUrlList();
        String urls = String.join(",", detailsImageUrlList);
        ProductDetails productDetails = new ProductDetails();
        productDetails.setImageUrls(urls);
        productDetails.setProductId(productId);
        productDetailsMapper.insert(productDetails);
        return 1;
    }

    @Override
    public Product selectProductById(Long id) {
        Product product = baseMapper.selectById(id);
        Long productId = product.getId();
        QueryWrapper<ProductSku> productSkuQueryWrapper = new QueryWrapper<>();
        productSkuQueryWrapper.eq("product_id", productId);
        List<ProductSku> productSkuList = productSkuMapper.selectList(productSkuQueryWrapper);

        QueryWrapper<ProductDetails> productDetailsQueryWrapper = new QueryWrapper<>();
        productDetailsQueryWrapper.eq("product_id", productId);
        ProductDetails productDetails = productDetailsMapper.selectOne(productDetailsQueryWrapper);
        String imageUrls = productDetails.getImageUrls();
        List<String> urlList = Arrays.asList(imageUrls.split(","));


        List<Long> skuIds = productSkuList.stream().map(sku -> {
            return sku.getId();
        }).collect(Collectors.toList());
        QueryWrapper<SkuStock> skuStockQueryWrapper = new QueryWrapper<>();
        skuStockQueryWrapper.in("sku_id", skuIds);
        List<SkuStock> skuStockList = skuStockMapper.selectList(skuStockQueryWrapper);
        System.out.println(skuStockList);

        Map<Long, Integer> stockMap = skuStockList.stream().collect(Collectors.toMap(skuStock -> skuStock.getSkuId(), skuStock -> skuStock.getAvailableNum()));
        for (ProductSku productSku : productSkuList) {
            productSku.setStockNum(stockMap.get(productSku.getId()));
        }


        product.setProductSkuList(productSkuList);
        product.setDetailsImageUrlList(urlList);
        return product;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateProduct(Product product) {

        //修改商品信息
        baseMapper.updateById(product);
        redisTemplate.opsForValue().set("data:getProduct:" + product.getId(), product);

        List<ProductSku> productSkuList = product.getProductSkuList();
        productSkuList.forEach(productSku -> {
            //修改商品SKU信息
            productSkuMapper.updateById(productSku);
            //同步缓存
            redisTemplate.opsForValue().set("product:sku：" + productSku.getId(), productSku);
            SkuPrice skuPrice = new SkuPrice();
            BeanUtils.copyProperties(productSku, skuPrice);
            redisTemplate.opsForValue().set("data:getSkuPrice:" + productSku.getId(), skuPrice);


            //修改商品库存
            SkuStock skuStock = skuStockMapper.selectOne(new LambdaQueryWrapper<SkuStock>().eq(SkuStock::getSkuId, productSku.getId()));
            skuStock.setTotalNum(productSku.getStockNum());
            int availableNum = skuStock.getTotalNum() - skuStock.getLockNum();
            skuStock.setAvailableNum(availableNum);
            skuStockMapper.updateById(skuStock);
            //同步缓存
            SkuStockVo skuStockVo = new SkuStockVo();
            redisTemplate.opsForValue().set("data:getSkuStock:" + productSku.getId(), skuStockVo);


        });

        //修改商品详细信息
        ProductDetails productDetails = productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductDetails>().eq(ProductDetails::getProductId, product.getId()));
        productDetails.setImageUrls(String.join(",", product.getDetailsImageUrlList()));
        productDetailsMapper.updateById(productDetails);
        //同步缓存
        redisTemplate.opsForValue().set("data:getProcductDetails:" + product.getId(), productDetails);

        List<ProductSku> productSkus = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, product.getId()));
        Map<String, Long> skuSpecValue = productSkus.stream().collect(Collectors.toMap(ProductSku::getSkuSpec, ProductSku::getId));
        redisTemplate.opsForValue().set("data:getSkuSpecValue:" + product.getId(), skuSpecValue);

        return 1;
    }


    @Override
    public int deleteProductByIds(Long[] ids) {
        baseMapper.deleteBatchIds(Arrays.asList(ids));
        List<ProductSku> productSkuList = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>()
                .in(ProductSku::getProductId, ids).select(ProductSku::getId));
        List<Long> skuIdList = productSkuList.stream().map(ProductSku::getId).collect(Collectors.toList());
        productSkuMapper.delete(new LambdaQueryWrapper<ProductSku>().in(ProductSku::getProductId, ids));
        skuStockMapper.delete(new LambdaQueryWrapper<SkuStock>().in(SkuStock::getSkuId, ids));
        productDetailsMapper.delete(new LambdaQueryWrapper<ProductDetails>().in(ProductDetails::getProductId, ids));

        return 1;
    }

    @Override
    public void updateAuditStatus(Long id, Integer auditStatus) {
        Product product = new Product();
        product.setId(id);
        if (auditStatus == 1) {
            product.setAuditStatus(1);
            product.setAuditMessage("审核通过");
        } else {
            product.setAuditStatus(-1);
            product.setAuditMessage("审核不通过");
        }
        baseMapper.updateById(product);
    }

    @Override
    public void updateStatus(Long id, Integer status) {
//        Product product = new Product();
//        product.setId(id);
//        if(status==1){
//            product.setStatus(1);
//        }else {
//            product.setStatus(-1);
//        }
//        baseMapper.updateById(product);
        Product product = new Product();
        product.setId(id);
        if (status == 1) {
            product.setStatus(1);

            //sku加入布隆过滤器
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("sku:bloom:filter");
            List<ProductSku> productSkuList = productSkuMapper.selectList(new LambdaQueryWrapper<ProductSku>().eq(ProductSku::getProductId, id));
            productSkuList.forEach(item -> {
                bloomFilter.add(item.getId());
            });
        } else {
            product.setStatus(-1);
        }
        baseMapper.updateById(product);

    }

    @Override
    public List<ProductSku> getTopSale() {
        return productSkuMapper.selectTopSale();
    }

    @Override
    public List<SkuQuery> getProductSkuList(SkuQuery skuQuery) {
        return productSkuMapper.selectProductSkuList(skuQuery);
    }

    @Override
    public ProductSku getProductSku(Long skuId) {
        ProductSku productSku = productSkuMapper.selectById(skuId);
        return productSku;
    }

    @Override
    public SkuPrice getSkuPrice(Long skuId) {
        ProductSku productSku = productSkuMapper.selectById(skuId);

        SkuPrice skuPrice = new SkuPrice();
        skuPrice.setMarketPrice(productSku.getMarketPrice());
        skuPrice.setSalePrice(productSku.getSalePrice());
        skuPrice.setSkuId(skuId);
        return skuPrice;
    }

    @Override
    public com.spzx.product.api.domain.vo.ProductDetails getProductDetails(Long productId) {
        ProductDetails productDetails = productDetailsMapper.selectOne(new QueryWrapper<ProductDetails>().eq("product_id", productId));
        return productDetails;
    }


    @Override
    public Map<String, Long> getSkuSpecValue(Long productId) {
        List<ProductSku> productSkus = productSkuMapper.selectList(new QueryWrapper<ProductSku>().eq("product_id", productId));
        Map<String, Long> specToSkuMap = productSkus.stream().collect(Collectors.toMap(ProductSku::getSkuSpec, ProductSku::getId));
        return specToSkuMap;
    }

    @Override
    public SkuStockVo getSkuStock(Long skuId) {
        SkuStockVo skuStockVo = new SkuStockVo();
        SkuStock skuStock = skuStockMapper.selectOne(new QueryWrapper<SkuStock>().eq("sku_id", skuId));
        skuStockVo.setAvailableNum(skuStock.getAvailableNum());
        skuStockVo.setSaleNum(skuStock.getSaleNum());
        skuStockVo.setSkuId(skuId);
        return skuStockVo;
    }

    @Override
    public List<SkuPrice> getSkuPriceList(List<Long> skuIdList) {
        List<ProductSku> productSkus = productSkuMapper.selectList(Wrappers.lambdaQuery(ProductSku.class).eq(ProductSku::getProductId, skuIdList));
        List<SkuPrice> skuPrices = productSkus.stream().map(productSku -> {
            SkuPrice skuPrice = new SkuPrice();
            skuPrice.setSkuId(productSku.getProductId());
            skuPrice.setSalePrice(productSku.getSalePrice());
            skuPrice.setMarketPrice(productSku.getMarketPrice());
            return skuPrice;
        }).collect(Collectors.toList());
        return skuPrices;
    }
    @SneakyThrows
    @Transactional
    @Override
    public String checkAndLock(String orderNo, List<SkuLockVo> skuLockVoList) {

        //锁库存，释放
        StringBuffer stringBuffer = new StringBuffer();
        String dataKey = "sku:lock:data:" +orderNo;
        String lockKey =  "sku:checkAndLock:" + orderNo;
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(lockKey, orderNo, 1, TimeUnit.HOURS);
        try {
            if (aBoolean) {
                for(SkuLockVo skuLockVo: skuLockVoList){
                    Long skuId = skuLockVo.getSkuId();
                    Integer skuNum = skuLockVo.getSkuNum();
                    Integer lockInt =  skuStockMapper.checkAndLock(skuId,skuNum);
                    if (lockInt <=0) {
                        stringBuffer.append("商品"+ skuLockVo.getSkuId()+"库存不足");
                        throw new Exception("商品" + skuLockVo.getSkuId()+"库存不足");
                    }
                }
            }
        } finally {
            redisTemplate.delete(lockKey);
        }
        return stringBuffer.toString();
    }

    @Override
    public void unlock(String orderNo) {
        String dataKey = "sku:lock:data:" + orderNo;
        // 锁定库存的分布式锁key，自己和自己的锁
        String lockKey = "sku:checkAndLock:" + orderNo;
        // 获得分布式锁
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(lockKey, orderNo, 1, TimeUnit.HOURS);
        try {
            if (aBoolean) {
                List<SkuLockVo> skuLockVos = (List<SkuLockVo>) this.redisTemplate.opsForValue().get(dataKey);
                for (SkuLockVo skuLockVo : skuLockVos) {
                    Integer i = skuStockMapper.unlockStock(skuLockVo.getSkuId(), skuLockVo.getSkuNum());
                }
                // 删除dataKey
                redisTemplate.delete(dataKey);
                System.out.println("productService unlock 释放库存");
            }
        } finally {
            redisTemplate.delete(lockKey);

        }
    }

    @Override
    public void minus(String orderNo) {
        String key ="sku:minus:"+ orderNo;
        String dataKey ="sku:lock:data:"+ orderNo;
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, orderNo, 1, TimeUnit.HOURS);
        if (aBoolean) return;
        List<SkuLockVo> skuLockVoList = (List<SkuLockVo>) this.redisTemplate.opsForValue().get(dataKey);
        if (CollectionUtils.isEmpty(skuLockVoList)){
            return;
        }
        skuLockVoList.forEach(skuLockVo -> {
            int row = skuStockMapper.minus(skuLockVo.getSkuId(),skuLockVo.getSkuNum());
            if (row == 0 ){
                this.redisTemplate.delete(key);
                throw  new ServiceException("减出库存失败");
            }
        });
        this.redisTemplate.delete(dataKey);

        System.out.println("productService minus 扣减库存");
    }
}














